package com.xuelang.pipeline.app.pipeline.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.xuelang.hiforce.base.cache.client.service.DistributeCacheManager;
import com.xuelang.pipeline.app.msg.MsgUserMessagesService;
import com.xuelang.pipeline.app.pipeline.PipelineService;
import com.xuelang.pipeline.app.pipeline.SonarqubeService;
import com.xuelang.pipeline.app.pipeline.TrackTaskService;
import com.xuelang.pipeline.app.resource.util.TektonUtil;
import com.xuelang.pipeline.app.resource.v1beta.pipeline.V1Beta1PipelineRun;
import com.xuelang.pipeline.client.common.constant.Constant;
import com.xuelang.pipeline.client.common.result.PageRecord;
import com.xuelang.pipeline.client.common.util.RedisHelper;
import com.xuelang.pipeline.client.msg.MsgConstant;
import com.xuelang.pipeline.client.msg.UserMessageSaveDTO;
import com.xuelang.pipeline.client.pipeline.dto.DeploymentUnitQuery;
import com.xuelang.pipeline.client.pipeline.dto.MeasDTO;
import com.xuelang.pipeline.client.pipeline.enums.*;
import com.xuelang.pipeline.client.resource.dto.ToolChainQuery;
import com.xuelang.pipeline.client.resource.enums.ToolChainTypeEnum;
import com.xuelang.pipeline.domain.pipeline.DeploymentUnit;
import com.xuelang.pipeline.domain.pipeline.Pipeline;
import com.xuelang.pipeline.domain.pipeline.TriggerSetting;
import com.xuelang.pipeline.domain.pipeline.service.DeploymentUnitDomainService;
import com.xuelang.pipeline.domain.pipeline.service.TriggerSettingDomainService;
import com.xuelang.pipeline.domain.resource.Environment;
import com.xuelang.pipeline.domain.resource.ToolChain;
import com.xuelang.pipeline.domain.resource.service.EnvironmentDomainService;
import com.xuelang.pipeline.domain.resource.service.ToolChainDomainService;
import com.xuelang.pipeline.domain.task.TaskInstance;
import com.xuelang.pipeline.domain.task.service.TaskInstanceDomainService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author liuyuan.ly
 * @since 2024/8/22 10:41
 */
@Service
@Slf4j
public class TrackTaskServiceImpl implements TrackTaskService {


    @Autowired
    private TaskInstanceDomainService taskInstanceDomainService;
    @Autowired
    private DeploymentUnitDomainService deploymentUnitDomainService;
    @Autowired
    private DistributeCacheManager redisHelper;
    @Autowired
    private EnvironmentDomainService environmentDomainService;
    @Autowired
    private ToolChainDomainService toolChainDomainService;
    @Autowired
    private SonarqubeService sonarqubeService;
    @Autowired
    private TriggerSettingDomainService triggerSettingDomainService;
    @Autowired
    private MsgUserMessagesService msgUserMessagesService;
    @Autowired
    private PipelineService pipelineService;

    void trackRunningTask(TaskInstance taskInstance, String taskRunName, Pipeline pipeline) {
        List<PipelineWorkflowServiceImpl.TaskResultInfo> resultInfoList = new ArrayList<>();
        //人工卡点
        if (taskRunName.contains(TaskDefCodeEnum.approve.getKey())) {
            if (StringUtils.isEmpty(taskInstance.getResultTip())) {
                PipelineWorkflowServiceImpl.TaskResultInfo resultInfo = getApproveTip(taskInstance.getCode());
                resultInfoList.add(resultInfo);
            }
        }
        //部署单处理
        if (taskRunName.contains(TaskDefCodeEnum.deploy.getKey())) {
            deploymentUnitProcess(taskInstance, pipeline);
        }
        //统一处理运行中提示，
        if (CollectionUtils.isNotEmpty(resultInfoList)) {
            taskInstance.setResultTip(JSON.toJSONString(resultInfoList));
        }
    }

    void trackSuccessTask(TaskInstance taskInstance, String taskRunName, Pipeline pipeline) {
        List<PipelineWorkflowServiceImpl.TaskResultInfo> resultInfoList = new ArrayList<>();
        List<PipelineWorkflowServiceImpl.TaskOutput> actionList = JSON.parseArray(taskInstance.getAction(), PipelineWorkflowServiceImpl.TaskOutput.class);
        if (taskRunName.contains(TaskDefCodeEnum.sonarqube.getKey()) && StringUtils.isEmpty(taskInstance.getResultTip())) {
            //显示扫描结果
            String environmentUuid = pipeline.getEnvironmentUuid();
            Environment environment = environmentDomainService.query(environmentUuid);
            String uniqueCode = pipeline.getComponentLabel() + "-" + environment.getCode();
            PipelineWorkflowServiceImpl.TaskResultInfo resultInfo = getTaskScanTip(uniqueCode);
            resultInfoList.add(resultInfo);
            //显示查看详情接口
            PipelineWorkflowServiceImpl.TaskOutput action = getSonarDetailAction(uniqueCode);
            actionList.add(action);
        }
        //统一处理运行action
        taskInstance.setAction(JSON.toJSONString(actionList));
        //统一处理运行resultInfo
        if (CollectionUtils.isNotEmpty(resultInfoList)) {
            taskInstance.setResultTip(JSON.toJSONString(resultInfoList));
        }
    }

    void trackFailedTask(TaskInstance taskInstance, String taskRunName, Pipeline pipeline, String errorTip) {
        List<PipelineWorkflowServiceImpl.TaskResultInfo> resultInfoList = new ArrayList<>();
        List<PipelineWorkflowServiceImpl.TaskOutput> actionList = JSON.parseArray(taskInstance.getAction(), PipelineWorkflowServiceImpl.TaskOutput.class);

        if (taskRunName.contains(TaskDefCodeEnum.sonarqube.getKey()) && StringUtils.isEmpty(taskInstance.getResultTip())) {
            HashMap<String, String> paramTaskMap = TektonUtil.parseTaskParamMap2O(taskInstance.getParams());
            if (paramTaskMap.containsKey(DeployTaskFieldEnum.alertInfo.name())) {
                String alertInfo = paramTaskMap.get(DeployTaskFieldEnum.alertInfo.name());
                List<PipelineWorkflowServiceImpl.AlertInfo> alertInfoList = JSON.parseArray(alertInfo, PipelineWorkflowServiceImpl.AlertInfo.class);
                PipelineWorkflowServiceImpl.TaskResultInfo alertHead = getTaskTip("扫描结果触发红线");
                resultInfoList.add(alertHead);
                StringBuffer sb = new StringBuffer();
                for (int i = 0; i < alertInfoList.size(); i++) {
                    PipelineWorkflowServiceImpl.AlertInfo ai = alertInfoList.get(i);
                    sb.append(RedLineInfoEnum.fromKey(ai.identifier).getValue())
                            .append("\t")
                            .append(ExpressionTypeEum.fromValue(ai.type).getKey())
                            .append("\t")
                            .append(ai.threshold);

                    if (i < alertInfoList.size() - 1) {
                        sb.append("\t且\t");
                    }
                }
                PipelineWorkflowServiceImpl.TaskResultInfo alertTipInfo = getTaskTip(sb.toString());
                resultInfoList.add(alertTipInfo);
                //显示扫描结果
                String environmentUuid = pipeline.getEnvironmentUuid();
                Environment environment = environmentDomainService.query(environmentUuid);
                String uniqueCode = pipeline.getComponentLabel() + "-" + environment.getCode();
                PipelineWorkflowServiceImpl.TaskResultInfo resultInfo = getTaskScanTip(uniqueCode);
                resultInfoList.add(resultInfo);
                //显示查看详情接口
                PipelineWorkflowServiceImpl.TaskOutput action = getSonarDetailAction(uniqueCode);
                actionList.add(action);
            }
        }
        //失败提示
        PipelineWorkflowServiceImpl.TaskResultInfo resultTip = getTaskTip(errorTip);
        if (!Objects.isNull(resultTip) && !taskRunName.contains(TaskDefCodeEnum.sonarqube.getKey())
                && !taskRunName.contains(TaskDefCodeEnum.approve.getKey())) {
            resultInfoList.add(resultTip);
        }

        //失败通知
        String pipelineCode = pipeline.getCode();
        TriggerSetting triggerSetting = triggerSettingDomainService.queryByPipelineCode(pipelineCode);
        if (Objects.nonNull(triggerSetting.getIsRunNotify()) && triggerSetting.getIsRunNotify().equals(YesOrNoEnum.YES.getValue())
                // 判断是否已经发送过此通知，若已发送，则无需再发送
                && !redisHelper.exists(Constant.PIPELINE_TASK_FAIL_MSG_SENT + taskInstance.getCode())) {
            List<String> toNotifyUserList = pipelineService.findPipelineNotifyReceiverList(pipelineCode);
            UserMessageSaveDTO userMessageSaveDTO = new UserMessageSaveDTO();
            userMessageSaveDTO.setMsgType(MsgConstant.MSG_TYPE_TEXT);
            userMessageSaveDTO.setTitle(String.format("流水线 %s 的任务失败", pipeline.getName()));
            userMessageSaveDTO.setContent(String.format("流水线编码为：%s；失败任务为： %s", pipelineCode, taskInstance.getName()));
            userMessageSaveDTO.setReceiveUserIds(toNotifyUserList);
            msgUserMessagesService.saveMessage(userMessageSaveDTO);
            // 设置redis
            redisHelper.setIfAbsent(Constant.PIPELINE_TASK_FAIL_MSG_SENT + taskInstance.getCode(), "sent", 1L, TimeUnit.DAYS);
        }
        //统一处理运行action
        taskInstance.setAction(JSON.toJSONString(actionList));
        //统一处理运行resultInfo
        if (CollectionUtils.isNotEmpty(resultInfoList)) {
            taskInstance.setResultTip(JSON.toJSONString(resultInfoList));
        }

    }


    /**
     * 处理部署单
     *
     * @param taskInstance
     * @param pipeline
     */
    @Override
    public void deploymentUnitProcess(TaskInstance taskInstance, Pipeline pipeline) {
        DeploymentUnitQuery query = DeploymentUnitQuery.builder().pipelineInstanceCode(taskInstance.getPipelineInstanceCode()).build();
        PageRecord<DeploymentUnit> record = deploymentUnitDomainService.pageByCondition(1, 1, query);
        List<DeploymentUnit> records = record.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            //这里需要处理，只能插入一次
            DeploymentUnit deploymentUnit = new DeploymentUnit();
            deploymentUnit.setComponentLabel(pipeline.getComponentLabel());
            deploymentUnit.setEnvironmentUuid(pipeline.getEnvironmentUuid());
            deploymentUnit.setPipelineInstanceCode(taskInstance.getPipelineInstanceCode());
            deploymentUnit.setCreateTime(taskInstance.getCreateTime());
            deploymentUnit.setCreatorId(taskInstance.getCreatorId());
            //唯一标识
            deploymentUnit.setTaskInstanceCode(taskInstance.getCode());
            String redisKey = Constant.DEPLOYMENT_VERSION_KEY + pipeline.getComponentLabel() + "." + pipeline.getEnvironmentUuid();
            deploymentUnit.setDeploymentVersion(redisHelper.incrby(redisKey, 1).toString());
            deploymentUnit.setDeploymentName(Constant.DEPLOYMENT_UNIT_NAME + "-" + deploymentUnit.getDeploymentVersion());
            deploymentUnit.setProgramVersion(pipeline.getCode());
            HashMap<String, String> hashMap = JSONObject.parseObject(taskInstance.getParams(), HashMap.class);
            deploymentUnit.setTargetReplicas(new BigDecimal(String.valueOf(hashMap.get(DeployTaskFieldEnum.replicas.getKey()))).intValueExact());
            deploymentUnit.setDeploymentWay(Integer.valueOf(hashMap.get(DeployTaskFieldEnum.deployStrategy.getKey())));
            deploymentUnit.setBatchCount(hashMap.containsKey(DeployTaskFieldEnum.batchesNum.getKey()) ? new BigDecimal(String.valueOf(hashMap.get(DeployTaskFieldEnum.batchesNum.getKey()))).intValueExact() : null);
            deploymentUnit.setDeploymentProgress(hashMap.containsKey(DeployTaskFieldEnum.batchesNum.getKey()) ? DeployUnitEnum.First.getKey() : null);
            deploymentUnitDomainService.add(deploymentUnit);
        }
    }

    @Override
    public void trackRunningPipeline(V1Beta1PipelineRun pipelineRun, Pipeline pipeline) {
        if (null != pipelineRun.getStatus() && CollectionUtils.isNotEmpty(pipelineRun.getStatus().getTaskRuns())) {
            pipelineRun.getStatus().getTaskRuns().forEach((taskRunName, taskRunStatus) -> {
                //在运行状态了
                if (taskRunStatus.getStatus().getStartTime() != null) {
                    if (null == taskRunStatus.getStatus().getConditions()) {
                        return;
                    }
                    String status = taskRunStatus.getStatus().getConditions().get(0).getReason();
                    TaskInstance taskInstance = taskInstanceDomainService.queryByTaskCode(taskRunName + "-pod");
                    taskInstance.setAction(getTaskAction(taskInstance, pipeline.getEnvironmentUuid()));
                    taskInstance.setStartTime(TektonUtil.getDate2offsetDate(taskRunStatus.getStatus().getStartTime()));
                    taskInstance.setTaskStatus(getTaskStatus(status));
                    if (null != taskRunStatus.getStatus().getCompletionTime()) {
                        taskInstance.setEndTime(TektonUtil.getDate2offsetDate(taskRunStatus.getStatus().getCompletionTime()));
                    }
                    taskInstance.setUpdateTime(new Date());

                    if (TaskInstanceEnum.success.getKey().equals(taskInstance.getTaskStatus())) {
                        trackSuccessTask(taskInstance, taskRunName, pipeline);
                    } else if (TaskInstanceEnum.failed.getKey().equals(taskInstance.getTaskStatus())) {
                        String errorTip = null == taskRunStatus.getStatus().getConditions().get(0).getStatus()
                                ? "error" : taskRunStatus.getStatus().getConditions().get(0).getStatus();
                        trackFailedTask(taskInstance, taskRunName, pipeline, errorTip);
                    } else {
                        trackRunningTask(taskInstance, taskRunName, pipeline);
                    }
                    taskInstanceDomainService.update(taskInstance);
                }
            });
        }
    }

    @Override
    public void trackSuccessPipeline(V1Beta1PipelineRun pipelineRun, Pipeline pipeline) {
        //成功后全部任务状态这里兜底处理
        pipelineRun.getStatus().getTaskRuns().forEach((taskRunName, taskRunStatus) -> {
            if (null == taskRunStatus.getStatus().getConditions()) {
                return;
            }
            String containerStatus = taskRunStatus.getStatus().getConditions().get(0).getReason();
            TaskInstance taskInstance = taskInstanceDomainService.queryByTaskCode(taskRunName + "-pod");
            taskInstance.setAction(getTaskAction(taskInstance, pipeline.getEnvironmentUuid()));
            taskInstance.setStartTime(TektonUtil.getDate2offsetDate(taskRunStatus.getStatus().getStartTime()));
            taskInstance.setTaskStatus(getTaskStatus(containerStatus));
            taskInstance.setEndTime(TektonUtil.getDate2offsetDate(taskRunStatus.getStatus().getCompletionTime()));
            taskInstance.setUpdateTime(new Date());
            trackSuccessTask(taskInstance, taskRunName, pipeline);
            taskInstanceDomainService.update(taskInstance);
        });
    }

    /**
     * sonar查看详情按钮处理
     *
     * @param uniqueCode
     * @return
     */
    private PipelineWorkflowServiceImpl.TaskOutput getSonarDetailAction(String uniqueCode) {
        String server = getSonarServer();
        PipelineWorkflowServiceImpl.TaskOutput taskOutput = new PipelineWorkflowServiceImpl.TaskOutput();
        taskOutput.setActionType(ActionTypeEnum.redirect.getKey());
        taskOutput.setActionUrl(server + "/project/issues?id=" + uniqueCode);
        taskOutput.setActionName("查看详情");
        taskOutput.setIcon("log-icon");
        return taskOutput;
    }

    private String getSonarServer() {
        ToolChainQuery query = new ToolChainQuery();
        query.setType(ToolChainTypeEnum.TYPE_QA.getTypeKey());
        PageRecord<ToolChain> toolChainPageRecord = toolChainDomainService.pageList(1, 1, query);
        String server = toolChainPageRecord.getRecords().get(0).getServer();
        return server;
    }

    /**
     * 代码扫描结果展示处理
     *
     * @param uniqueCode
     * @return
     */
    private PipelineWorkflowServiceImpl.TaskResultInfo getTaskScanTip(String uniqueCode) {
        List<Map<String, String>> data = new ArrayList<>();
        MeasDTO measDTO = sonarqubeService.getSonarScanResult(uniqueCode);
        measDTO.getComponent().getMeasures().forEach(meas -> {
            HashMap<String, String> tipMap = new HashMap<>();
            tipMap.put("value", meas.getValue());
            tipMap.put("label", RedLineInfoEnum.fromKey(meas.getMetric()).getValue());
            tipMap.put("color", "red");
            data.add(tipMap);
        });
        return PipelineWorkflowServiceImpl.TaskResultInfo.builder().type(TaskResultTypeEnum.bottomInfo.getKey()).data(data).position("center").build();
    }
}
